fix: reconcile routeselected handlers and persist selected alternative#489
Conversation
Merge two separate lrmControl.on('routeselected') listeners into a single
handler in index.js. The state.js listener only set
this.options.alternative but never called this.update(), so the selected
alternative was never persisted to the URL.
Changes:
- Remove routeselected listener from state.js
- Add alternative tracking + state.update() to the remaining handler
- Switch to URL-specified alternative on initial load (LRM always
selects route[0] first), with fallback if the alternative no longer
exists
- Extract alternative-resolution logic into pure
resolveInitialAlternative() in src/route_alternative.js
- Add 18 unit tests covering no-switch, switch, fallback, and edge cases
Closes #455
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR addresses #455 by consolidating routeselected handling into src/index.js and ensuring the selected route alternative is persisted into (and restored from) URL state, including a first-load switch away from LRM’s default route[0] when ?alt=N is present.
Changes:
- Remove the duplicate
routeselectedlistener fromsrc/state.jsto avoid double-dispatch and diverging behavior. - Add first-load alternative resolution + URL persistence for selected alternatives in
src/index.js. - Introduce
src/route_alternative.jswith accompanying Jest tests to determine when/how to switch to a URL-specified alternative.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
src/state.js |
Removes redundant routeselected listener so alternative selection is handled in one place. |
src/index.js |
Centralizes routeselected logic: resolves initial alternative from URL and persists selected alternative via state.update(). |
src/route_alternative.js |
Adds helper to decide whether to re-fire routeselected for a URL-requested alternative. |
test/route_alternative.test.js |
Adds unit coverage for initial-alternative resolution behavior and edge cases. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| var index = Number(desiredAlt); | ||
| if (!index || index < 0) return null; // 0, NaN, undefined, null, "", negative | ||
| if (route.routesIndex === index) return null; // already on the desired route |
There was a problem hiding this comment.
Good catch. Added index % 1 !== 0 to the guard clause so non-integer values like 1.5 (or the string "1.5") are rejected before they reach the array index lookup. This covers floats and Infinity, and works across all JS environments (unlike Number.isInteger).
| test('desiredAlt is negative', function() { | ||
| var route = makeRoute(0); | ||
| var result = resolveInitialAlternative(route, [makeRoute(1)], -1); | ||
| expect(result).toBeNull(); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Added two regression tests: one for a float literal 1.5 and one for a float string "1.5" — both now correctly return null.
…ve resolution Non-integer values like 1.5 (which could come from URL query strings) would produce allRoutes[1.5] = undefined, causing an undefined route payload and potential re-entrant routeselected firing. Add index % 1 !== 0 guard and regression tests for float and float-string inputs.
Prohibit cute/whimsical names; require descriptive, functional names for variables and functions.
Summary
Fixes #455 — merges two separate lrmControl.on('routeselected') listeners into a single handler and fixes a bug where the selected route alternative was never persisted to the URL.
Problem
Changes
Behavior
AI assistance: Claude Code helped with extracting the pure helper, writing test cases, and structuring the PR.